<template>
  <el-main>
    <el-card class="device-list-card">
      <!-- 添加页面标题 -->
      <div class="page-header">
        <div class="page-title">设备管理</div>
        <div class="page-subtitle">设备列表与信息管理</div>
      </div>
      
      <div class="device-list-header">
        <el-input v-model="searchText" placeholder="搜索名称/编码/型号" clearable class="search-input" />
        <div class="device-list-actions">
          <el-button v-if="userRole === 'admin' || userRole === 'superadmin'" type="primary" @click="openAddDialog">添加设备</el-button>
          <el-button type="primary" @click="exportExcel">导出Excel</el-button>
          <el-button type="success" @click="downloadTemplate">下载模板</el-button>
          <el-button type="warning" @click="showImportDialog = true">批量导入</el-button>
        </div>
      </div>
      <el-table :data="pagedDevices" border stripe style="width:100%;background:#fff;" :empty-text="loading ? '加载中...' : '暂无数据'">
        <el-table-column prop="status" label="状态" min-width="100">
          <template #default="scope">
            <el-tag
              :type="
                scope.row.status === '正常运行' ? 'success' :
                scope.row.status === '带病运行' ? 'warning' :
                scope.row.status === '故障维修' ? 'danger' :
                scope.row.status === '备用' ? 'info' :
                scope.row.status === '报废' ? 'default' : ''
              "
              effect="plain"
            >
              {{ scope.row.status || '未知' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="name" label="设备名称" min-width="120">
          <template #default="scope">
            <el-link type="primary" @click="goDetail(scope.row)">{{ scope.row.name || '无' }}</el-link>
          </template>
        </el-table-column>
        <el-table-column prop="model" label="规格型号" min-width="100">
          <template #default="scope">
            <el-link type="primary" @click="goDetail(scope.row)">{{ scope.row.model || '无' }}</el-link>
          </template>
        </el-table-column>
        <el-table-column prop="code" label="设备编码" min-width="180">
          <template #default="scope">
            <el-link type="primary" @click="goDetail(scope.row)">{{ scope.row.code || '无' }}</el-link>
          </template>
        </el-table-column>
        <el-table-column prop="type" label="设备类型" min-width="100" />
        <el-table-column prop="location" label="安装地点" min-width="100" />
        <el-table-column prop="manufacturer" label="生产厂家" min-width="100" />
        <el-table-column label="二维码" width="100">
          <template #default="scope">
            <qrcode-vue :value="getDeviceUrl(scope.row)" :size="60" />
          </template>
        </el-table-column>
        <el-table-column prop="image" label="图片" width="100">
          <template #default="scope">
            <img v-if="scope.row.image && scope.row.image.url"
                 :src="getThumbUrl(scope.row.image.url)"
                 alt="设备图片"
                 class="device-thumb"
                 style="cursor:pointer;"
                 loading="lazy"
                 @click="handleImageClick(scope.row.image.url)" />
          </template>
        </el-table-column>
        <el-table-column prop="calibrationPlan" label="校正方案" min-width="100" />
        <el-table-column label="操作" width="260">
          <template #default="scope">
            <div style="display:flex;gap:8px;flex-wrap:nowrap;align-items:center;">
              <!-- <el-button size="small" @click="goDetail(scope.row)">详情</el-button> -->
              <el-button v-if="userRole === 'admin' || userRole === 'superadmin'" size="small" @click="editDevice(scope.row)">编辑</el-button>
              <el-button v-if="userRole === 'admin' || userRole === 'superadmin'" size="small" type="danger" @click="deleteDevice(scope.row.objectId)">删除</el-button>
              <el-button
                v-if="userRole === 'admin' || userRole === 'superadmin'"
                size="small"
                :type="scope.row.calibrationPlan === '每班校正' ? 'primary' : 'default'"
                @click="toggleCalibrationPlan(scope.row)"
              >
                {{ scope.row.calibrationPlan || '无需校正' }}
              </el-button>
            </div>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
        style="margin:20px 0; text-align:center;"
        background
        layout="prev, pager, next"
        :total="filteredDevices.length"
        :page-size="pageSize"
        v-model:current-page="currentPage"
      />
    </el-card>
    <!-- 添加/编辑设备弹窗 -->
    <el-dialog v-if="userRole === 'admin' || userRole === 'superadmin'" v-model="showDialog" :title="editingDevice ? '编辑设备' : '添加设备'">
      <el-form :model="newDevice" label-width="100px">
        <el-form-item label="设备名称"><el-input v-model="newDevice.name" required /></el-form-item>
        <el-form-item label="设备图片">
          <el-upload :show-file-list="false" :before-upload="beforeImageUpload" accept="image/*">
            <el-button>上传图片</el-button>
          </el-upload>
          <img v-if="newDevice.imageUrl" :src="newDevice.imageUrl" alt="设备图片" class="device-thumb" />
        </el-form-item>
        <el-form-item label="规格型号"><el-input v-model="newDevice.model" /></el-form-item>
        <el-form-item label="设备编码"><el-input v-model="newDevice.code" /></el-form-item>
        <el-form-item label="设备类型">
          <el-select v-model="newDevice.type" placeholder="请选择设备类型">
            <el-option label="办公设备" value="办公设备" />
            <el-option label="实验设备" value="实验设备" />
            <el-option label="生产设备" value="生产设备" />
            <el-option label="其他" value="其他" />
          </el-select>
        </el-form-item>
        <el-form-item label="安装地点">
          <el-select v-model="newDevice.location" filterable allow-create default-first-option placeholder="请选择或输入安装地点">
            <el-option v-for="loc in locations" :key="loc" :label="loc" :value="loc" />
          </el-select>
        </el-form-item>
        <el-form-item label="生产厂家"><el-input v-model="newDevice.manufacturer" /></el-form-item>
        <el-form-item label="负责人"><el-input v-model="newDevice.manager" /></el-form-item>
        <el-form-item label="到货日期">
          <el-date-picker v-model="newDevice.arrivalDate" type="date" />
        </el-form-item>
        <el-form-item label="校正方案">
          <el-select v-model="newDevice.calibrationPlan" placeholder="请选择">
            <el-option label="每班校正" value="每班校正" />
            <el-option label="无需校正" value="无需校正" />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showDialog = false">取消</el-button>
        <el-button type="primary" @click="editingDevice ? updateDevice() : addDevice()">保存</el-button>
      </template>
    </el-dialog>
    <el-dialog v-model="showImageDialog" width="400px" :show-close="true" title="图片预览" center>
      <img :src="previewImageUrl" alt="设备大图" style="max-width:100%;max-height:60vh;display:block;margin:0 auto;" />
    </el-dialog>
    <el-dialog v-model="showImportDialog" title="批量导入设备" width="400px">
      <el-upload
        :show-file-list="false"
        :before-upload="handleImportExcel"
        accept=".xlsx,.xls"
      >
        <el-button type="primary">选择Excel文件</el-button>
      </el-upload>
      <div v-if="importResult" style="margin-top:16px;">
        <div v-if="importResult.success">导入成功：{{importResult.success}} 条</div>
        <div v-if="importResult.fail && importResult.fail.length">导入失败：{{importResult.fail.length}} 条<br/>{{importResult.fail.join(', ')}}</div>
      </div>
      <template #footer>
        <el-button @click="showImportDialog = false">关闭</el-button>
      </template>
    </el-dialog>
  </el-main>
</template>

<script setup>
import { ref, computed, onMounted, watch } from 'vue'
import AV from '../leancloud'
import QrcodeVue from 'qrcode.vue'
import { ElMessage } from 'element-plus'
import imageCompression from 'browser-image-compression'
import { useRouter } from 'vue-router'
import locations from '../assets/locations'
import * as XLSX from 'xlsx'
import { saveAs } from 'file-saver'

const router = useRouter()

const devices = ref([])
const searchText = ref('')
const currentPage = ref(1)
const pageSize = ref(8)
const showDialog = ref(false)
const newDevice = ref({
  name: '', imageFile: null, imageUrl: '', model: '', code: '', location: '', manager: '', arrivalDate: '', manufacturer: '', calibrationPlan: '', status: '', type: ''
})
const editingDevice = ref(null)
const loading = ref(false)
const previewImageUrl = ref('')
const showImageDialog = ref(false)
const userRole = ref(localStorage.getItem('userRole') || 'user')
const showImportDialog = ref(false)
const importResult = ref(null)

async function fetchDevices() {
  loading.value = true
  try {
    const query = new AV.Query('Device')
    query.select(['name','model','code','location','manager','arrivalDate','manufacturer','status','image','calibrationPlan','type'])
    query.limit(1000)
    const results = await query.find()
    devices.value = results.map(d => d.toJSON())
  } finally {
    loading.value = false
  }
}
onMounted(() => {
  fetchDevices()
  // 检查是否需要刷新（如详情页切换了状态）
  if (localStorage.getItem('deviceListShouldRefresh') === '1') {
    fetchDevices()
    localStorage.removeItem('deviceListShouldRefresh')
  }
})
// 监听路由切换自动刷新
watch(() => router.currentRoute.value.fullPath, () => {
  if (localStorage.getItem('deviceListShouldRefresh') === '1') {
    fetchDevices()
    localStorage.removeItem('deviceListShouldRefresh')
  }
})

const filteredDevices = computed(() => {
  if (!searchText.value) return devices.value
  const t = searchText.value.trim().toLowerCase()
  return devices.value.filter(d =>
    (d.name && d.name.toLowerCase().includes(t)) ||
    (d.code && d.code.toLowerCase().includes(t)) ||
    (d.model && d.model.toLowerCase().includes(t))
  )
})
const pagedDevices = computed(() => {
  const start = (currentPage.value - 1) * pageSize.value
  return filteredDevices.value.slice(start, start + pageSize.value)
})

function openAddDialog() {
  if (userRole.value !== 'admin' && userRole.value !== 'superadmin') {
    ElMessage.warning('只有管理员才能添加设备')
    return
  }
  editingDevice.value = null
  newDevice.value = { name: '', imageFile: null, imageUrl: '', model: '', code: '', location: '', manager: '', arrivalDate: '', manufacturer: '', calibrationPlan: '', status: '', type: '' }
  showDialog.value = true
}
const beforeImageUpload = async (file) => {
  // 压缩图片
  const compressedFile = await imageCompression(file, { maxSizeMB: 0.2, maxWidthOrHeight: 800, useWebWorker: true })
  newDevice.value.imageFile = compressedFile
  newDevice.value.imageUrl = URL.createObjectURL(compressedFile)
  return false
}
async function addDevice() {
  if (userRole.value !== 'admin' && userRole.value !== 'superadmin') {
    ElMessage.warning('只有管理员才能添加设备')
    return
  }
  // 如果未填写编码，自动生成
  if (!newDevice.value.code || !String(newDevice.value.code).trim()) {
    newDevice.value.code = generateDeviceCode();
  }
  const Device = AV.Object.extend('Device')
  const d = new Device()
  Object.entries(newDevice.value).forEach(([k, v]) => {
    if (k === 'imageFile' || k === 'imageUrl') return
    if (k === 'arrivalDate' && v) {
      d.set('arrivalDate', typeof v === 'string' ? v : new Date(v).toISOString())
    } else if (v) {
      d.set(k, v)
    }
  })
  if (newDevice.value.imageFile) {
    const avFile = new AV.File(newDevice.value.imageFile.name, newDevice.value.imageFile)
    await avFile.save()
    d.set('image', avFile)
  }
  const acl = new AV.ACL()
  acl.setPublicReadAccess(true)
  acl.setPublicWriteAccess(true)
  d.setACL(acl)
  await d.save()
  ElMessage.success('添加成功')
  showDialog.value = false
  fetchDevices()
}
function editDevice(device) {
  if (userRole.value !== 'admin' && userRole.value !== 'superadmin') {
    ElMessage.warning('只有管理员才能编辑设备')
    return
  }
  editingDevice.value = device
  Object.keys(newDevice.value).forEach(k => {
    newDevice.value[k] = device[k] || ''
  })
  newDevice.value.imageFile = null
  newDevice.value.imageUrl = device.image ? device.image.url : ''
  showDialog.value = true
}
async function updateDevice() {
  if (userRole.value !== 'admin') {
    ElMessage.warning('只有管理员才能编辑设备')
    return
  }
  const d = AV.Object.createWithoutData('Device', editingDevice.value.objectId)
  Object.entries(newDevice.value).forEach(([k, v]) => {
    if (k === 'imageFile' || k === 'imageUrl') return
    if (k === 'arrivalDate' && v) {
      d.set('arrivalDate', typeof v === 'string' ? v : new Date(v).toISOString())
    } else if (v) {
      d.set(k, v)
    } else {
      d.unset(k)
    }
  })
  if (newDevice.value.imageFile) {
    const avFile = new AV.File(newDevice.value.imageFile.name, newDevice.value.imageFile)
    await avFile.save()
    d.set('image', avFile)
  }
  await d.save()
  ElMessage.success('保存成功')
  showDialog.value = false
  fetchDevices()
}
async function deleteDevice(objectId) {
  if (userRole.value !== 'admin' && userRole.value !== 'superadmin') {
    ElMessage.warning('只有管理员才能删除设备')
    return
  }
  try {
    const device = AV.Object.createWithoutData('Device', objectId)
    await device.destroy()
    fetchDevices()
  } catch (e) {
    ElMessage.error('删除失败：' + (e.message || e.rawMessage))
  }
}
function goDetail(device) {
  router.push({ path: '/device-detail', query: { id: device.objectId } })
}
function exportExcel() {
  const headers = ['状态','设备名称','规格型号','设备编码','设备类型','安装地点','生产厂家','负责人','到货日期','校正方案']
  const data = filteredDevices.value.map(d => [
    d.status || '',
    d.name || '',
    d.model || '',
    d.code || '',
    d.type || '',
    d.location || '',
    d.manufacturer || '',
    d.manager || '',
    d.arrivalDate ? new Date(d.arrivalDate).toLocaleDateString() : '',
    d.calibrationPlan || ''
  ])
  const ws = XLSX.utils.aoa_to_sheet([headers, ...data])
  const wb = XLSX.utils.book_new()
  XLSX.utils.book_append_sheet(wb, ws, '设备列表')
  const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'array' })
  saveAs(new Blob([wbout], { type: 'application/octet-stream' }), '设备列表.xlsx')
}
function downloadTemplate() {
  const headers = ['状态','设备名称','规格型号','设备编码','设备类型','安装地点','生产厂家','负责人','到货日期','校正方案']
  const ws = XLSX.utils.aoa_to_sheet([headers])
  const wb = XLSX.utils.book_new()
  XLSX.utils.book_append_sheet(wb, ws, '设备模板')
  const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'array' })
  saveAs(new Blob([wbout], { type: 'application/octet-stream' }), '设备导入模板.xlsx')
}
function getDeviceUrl(device) {
  const ip = '192.168.10.47'
  const port = '5173'
  const token = localStorage.getItem('sessionToken')
  return `http://${ip}:${port}/#/device-detail?id=${device.objectId}${token ? `&token=${token}` : ''}`
}
function handleImageClick(url) {
  previewImageUrl.value = url
  showImageDialog.value = true
}
function getThumbUrl(url) {
  if (!url) return ''
  return url + '?imageView2/1/w/60/h/60'
}

function generateDeviceCode() {
  // 生成一个大写字母+六位数字的设备编码，如 D123456
  const letter = String.fromCharCode(65 + Math.floor(Math.random() * 26));
  const number = Math.floor(100000 + Math.random() * 900000); // 保证六位
  return `${letter}${number}`;
}

async function handleImportExcel(file) {
  importResult.value = null
  const reader = new FileReader()
  reader.onload = async (e) => {
    const data = new Uint8Array(e.target.result)
    const workbook = XLSX.read(data, { type: 'array' })
    const sheet = workbook.Sheets[workbook.SheetNames[0]]
    const rows = XLSX.utils.sheet_to_json(sheet, { header: 1 })
    const headers = rows[0]
    const body = rows.slice(1).filter(row => row.length && row.some(cell => cell))
    let success = 0, fail = []
    for (const row of body) {
      // 新模板顺序：状态、设备名称、规格型号、设备编码、设备类型、安装地点、生产厂家、负责人、到货日期、校正方案
      const [status, name, model, code, type, location, manufacturer, manager, arrivalDate, calibrationPlan] = row
      if (!name) { fail.push(`缺少设备名称(${row.join(',')})`); continue }
      let deviceCode = code && String(code).trim() ? String(code).trim() : generateDeviceCode()
      try {
        const Device = AV.Object.extend('Device')
        const d = new Device()
        d.set('name', name)
        d.set('model', model || '')
        d.set('code', deviceCode)
        d.set('type', type || '')
        d.set('location', location || '')
        d.set('manufacturer', manufacturer || '')
        d.set('manager', manager || '')
        if (arrivalDate) d.set('arrivalDate', typeof arrivalDate === 'string' ? arrivalDate : new Date(arrivalDate).toISOString())
        d.set('calibrationPlan', calibrationPlan || '')
        d.set('status', status || '正常运行')
        const acl = new AV.ACL()
        acl.setPublicReadAccess(true)
        acl.setPublicWriteAccess(true)
        d.setACL(acl)
        await d.save()
        success++
      } catch (e) {
        fail.push(name)
      }
    }
    importResult.value = { success, fail }
    fetchDevices()
  }
  reader.readAsArrayBuffer(file)
  return false
}

function toggleCalibrationPlan(row) {
  if (userRole.value !== 'admin' && userRole.value !== 'superadmin') {
    ElMessage.warning('只有管理员才能修改校正方案')
    return
  }
  if (!row || !row.objectId) return
  const next = row.calibrationPlan === '每班校正' ? '无需校正' : '每班校正'
  const d = AV.Object.createWithoutData('Device', row.objectId)
  d.set('calibrationPlan', next)
  d.save().then(() => {
    row.calibrationPlan = next
    ElMessage.success('校正方案已切换为：' + next)
    fetchDevices()
  }).catch(e => {
    ElMessage.error('切换失败：' + (e.message || e.rawMessage))
  })
}
</script>

<style scoped>
.device-list-card {
  margin: 24px auto;
  /* max-width: 1200px; */
  width: 100%;
  box-sizing: border-box;
}
.page-header {
  text-align: center;
  margin-bottom: 20px;
  padding-bottom: 10px;
  border-bottom: 1px solid #eee;
}
/* 页面标题样式已移至全局样式文件 */
.device-list-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
  flex-wrap: wrap;
}
.search-input {
  width: 220px;
  margin-right: 12px;
}
.device-list-actions {
  display: flex;
  gap: 12px;
}

/* 统一按钮样式 */
.device-list-actions .el-button {
  font-weight: 600;
  font-size: 14px;
  padding: 8px 16px;
  border-radius: 6px;
  gap: 6px;
  height: 36px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}

.device-list-actions .el-button[type="primary"] {
  background: linear-gradient(135deg, #409eff 0%, #337ecc 100%);
  border: 1px solid #409eff;
  color: white;
}

.device-list-actions .el-button[type="primary"]:hover {
  background: linear-gradient(135deg, #337ecc 0%, #2d5aa0 100%);
  border-color: #337ecc;
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(64, 158, 255, 0.3);
}

.device-list-actions .el-button[type="success"] {
  background: linear-gradient(135deg, #67c23a 0%, #529b2e 100%);
  border: 1px solid #67c23a;
  color: white;
}

.device-list-actions .el-button[type="success"]:hover {
  background: linear-gradient(135deg, #529b2e 0%, #3f7c23 100%);
  border-color: #529b2e;
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(103, 194, 58, 0.3);
}

.device-list-actions .el-button[type="warning"] {
  background: linear-gradient(135deg, #e6a23c 0%, #cf9236 100%);
  border: 1px solid #e6a23c;
  color: white;
}

.device-list-actions .el-button[type="warning"]:hover {
  background: linear-gradient(135deg, #cf9236 0%, #b88230 100%);
  border-color: #cf9236;
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(230, 162, 60, 0.3);
}

/* 表格中的按钮样式 */
.el-table .el-button {
  font-weight: 600;
  font-size: 12px;
  padding: 4px 8px;
  border-radius: 4px;
  gap: 4px;
  height: 28px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}

.el-table .el-button[type="danger"] {
  background: linear-gradient(135deg, #f56c6c 0%, #e74c3c 100%);
  border: 1px solid #f56c6c;
  color: white;
}

.el-table .el-button[type="danger"]:hover {
  background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%);
  border-color: #e74c3c;
  transform: translateY(-1px);
  box-shadow: 0 3px 6px rgba(245, 108, 108, 0.3);
}

/* 确保按钮内容居中 */
.el-button .el-button__content {
  display: flex;
  justify-content: center;
  align-items: center;
}
.device-thumb {
  width: 60px;
  height: 60px;
  object-fit: cover;
  border-radius: 6px;
  background: #f5f5f5;
  border: 1px solid #eee;
}
@media (max-width: 900px) {
  .device-list-card {
    max-width: 100vw;
    margin: 8px 0;
  }
  .page-header {
    text-align: left;
    padding-left: 10px;
    padding-bottom: 5px;
  }
  /* 页面标题样式已移至全局样式文件 */
  .device-list-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }
  .search-input {
    width: 100%;
    margin-right: 0;
  }
  .device-list-actions {
    width: 100%;
    gap: 8px;
    flex-wrap: wrap;
  }
}
</style> 